package internal

import (
	"reflect"
	"time"
	"game-server/base"
	"game-server/conf"
	"game-server/log"
	"game-server/msg"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"io/ioutil"
	"net/http"
	"net/url"
	"fmt"
	"math/rand"

	"encoding/json"
	"unsafe"
)

// 账号信息表
type TAccount struct {
	Uin        uint      `orm:"pk;auto;column(uin)"`
	Passwd     string    `orm:"size(64)"`
	Nick       string    `orm:"size(16);default();index"`
	UserId     int32     `orm:"column(userId)"`
	Cards      int32     `orm:"default(0)"`
	Golden     int32     `orm:"default(0)"`
	Score      int32     `orm:"default(0)"`
	OpenId     string    `orm:"size(64);column(openId)"`
	Unionid    string    `orm:"size(64)"`
	HeadUrl    string    `orm:"size(200);column(headUrl)"`
	Sex        int32     `orm:"default(0)"`
	Country    string    `orm:"size(10)"`
	Province   string    `orm:"size(10)"`
	City       string    `orm:"size(10)"`
	Identity   string    `orm:"size(20)"`
	Name       string    `orm:"size(10)"`
	Phone      string    `orm:"size(11)"`
	Invitation int32     `orm:"default(0)"`
	Ticket     int32     `orm:"default(0)"`
	CreateTime time.Time `orm:"auto_now_add;type(datetime)"`
	UpdateTime time.Time `orm:"auto_now;type(datetime)"`
	BirdId     int32     `orm:"default(0)"`
	BirdIdNum     int32  `orm:"default(0)"`
	NickNum     int32    `orm:"default(0)"`
	Items    string      `orm:"size(128)"`
	UsedItem    int32    `orm:"default(0)"`
}

// 登录日志表
type TLogLogin struct {
	Id         uint64    `orm:"pk;auto"`
	OpTime     time.Time `orm:"auto_now_add;type(datetime)"`
	OpIp       string    `orm:"size(32)"`
	GeoPoint   string    `orm:"size(32)"`
	LogOutTime time.Time `orm:"auto_now;type(datetime);column(logout_time)"`
	OpenId     string    `orm:"size(32)"`
}


// 设置引擎为 INNODB
func (u *TAccount) TableEngine() string {
	return "INNODB"
}

func (u *TLogLogin) TableEngine() string {
	return "INNODB"
}

// 设置表名
func (u *TAccount) TableName() string {
	return "tAccount"
}

func (u *TLogLogin) TableName() string {
	return "tLogLogin"
}


// 多字段索引
func (u *TLogLogin) TableIndex() [][]string {
	return [][]string{
		[]string{"OpenId", "OpTime"},
	}
}

func init() {
	// 实名认证注册
	//handler(&msg.MsgVerification{}, handleVerification)
	//// 发起实名认证注册
	//handler(&msg.MsgCheckVerity{}, handleCheckVerity)
	//// 是否绑定邀请码消息注册
	//handler(&msg.MsgCheckInvite{}, handleCheckInvite)
	//// 发起绑定邀请码消息注册
	//handler(&msg.MsgInvitation{}, handleInvitation)
	//// 预借单消息注册
	//handler(&msg.MsgAdvanceList{}, handleAdvanceList)
	//// 预借房卡消息注册
	//handler(&msg.MsgAdvanceCard{}, handleAdvanceCard)
	//// 更新激活状态和预存上限消息注册
	//handler(&msg.MsgBindUpdate{}, handleBindUpdate)
	//// 添加邀请码消息注册
	//handler(&msg.MsgInsertCode{}, handleInsertCode)
	//// 预结算清单消息注册
	//handler(&msg.MsgSettleAccounts{}, handleSettleAccounts)
	//// 预结算清单消息注册
	//handler(&msg.MsgTurnplate{}, handleTurnplate)
	//// 预结算清单消息注册
	//handler(&msg.MsgTurnplateReceive{}, handleTurnplateReceive)
	//// 大转盘消息处理
	//handler(&msg.MsgPortalTurnplate{}, handlePortalTurnplate)

	orm.RegisterDriver("mysql", orm.DRMySQL)

	fmt.Println("------------------", conf.Server.User+":"+conf.Server.Passwd+"@tcp("+conf.Server.Host+")/"+conf.Server.Db+"?charset=utf8&loc=Asia%2FShanghai")
	orm.RegisterDataBase("default", "mysql", conf.Server.User+":"+conf.Server.Passwd+"@tcp("+conf.Server.Host+")/"+conf.Server.Db+"?charset=utf8&loc=Asia%2FShanghai")
	//
	orm.SetMaxIdleConns("default", conf.Server.MaxIdle)
	orm.SetMaxOpenConns("default", conf.Server.MaxOpen)

	//orm.Debug = true

	orm.RegisterModel( new(TAccount), new(TLogLogin))

	// create table
	orm.RunSyncdb("default", false, false)

	// 初始化数据
	loadData()

	// 初始化定时任务
	skeleton.AfterFunc(time.Second*time.Duration(conf.Server.DataToMysql), onTimer)


}

func handler(m interface{}, h interface{}) {
	skeleton.RegisterChanRPC(reflect.TypeOf(m), h)
}

// 定时任务
func onTimer() {
	checkRoom()
	saveData()
	skeleton.AfterFunc(time.Second*time.Duration(conf.Server.DataToMysql), onTimer)

}

// 内存数据持久化redis
func saveData() {
	log.Debug("saveData==============RoomList",base.RoomList)
	base.Put("roomList", 0, base.RoomList)
	base.Put("roomOver", 0, base.RoomOver)
	base.Put("pokerList", 0, base.PokerList)
	base.Put("pokerOver", 0, base.PokerOver)
	base.Put("exitRoom", 0, base.ExitRoom)
	base.Put("roomTotal", 0, base.RoomTotal)
	base.Put("roomPool", 0, base.RoomPool)
	base.Put("userList", 0, base.UserList)
	log.Debug("saveData==============UserList",base.UserList)
}

// 初始化加载redis数据到内存中
func loadData() {
	//redisDB,err :=strconv.Atoi(conf.Server.RedisDb)

	roomList := base.Get("roomList",0)
	fmt.Println("roomList",roomList)
	if roomList != nil {
		base.RoomList = roomList.([]int32)
	}

	fmt.Println("roomList",roomList)
	fmt.Println("base.RoomList",base.RoomList)


	roomOver := base.Get("roomOver", 0)
	if roomOver != nil {
		base.RoomOver = roomOver.([]int32)
	}

	exitRoom := base.Get("exitRoom", 0)
	if exitRoom != nil {
		base.ExitRoom = exitRoom.([]int32)
	}

	roomTotal := base.Get("roomTotal", 0)
	if roomTotal != nil {
		base.RoomTotal = roomTotal.([]int32)
	}

	if len(base.RoomTotal) == 0 {
		base.RoomTotal = []int32{100000}
		for i := int(base.RoomTotal[0]); i < int(base.RoomTotal[0]+100); i++ {
			roomNo := int32(i)
			base.RoomPool = append(base.RoomPool, roomNo)
		}
		log.Info("ROOM Pool = ", base.RoomPool, len(base.RoomPool))
	}

	roomPool := base.Get("roomPool", 0)
	if roomPool != nil {
		base.RoomPool = roomPool.([]int32)
	}

	userList := base.Get("userList", 0)
	if userList != nil {
		base.UserList = userList.([]int32)
	}
}

// 检查房间数据并持久化
func checkRoom() {
	//o := orm.NewOrm()
	log.Info("RoomOver: RoomOver = ", base.RoomList, len(base.RoomList))
	if len(base.RoomList) > 0 {
		for k := 0; k < len(base.RoomList); k++ {
			log.Info("RoomList: key = ", k)
			v := base.RoomList[k]
			log.Info("RoomList: v = ", v)

			roomInfo := base.Get("room", v)
			log.Info("RoomList: roomInfo = ", roomInfo)
			if roomInfo != nil {
				room := roomInfo.(base.Pk)
				log.Info("RoomList: room.Destroy  = ", room.Destroy )

				if room.Destroy {
					log.Info("RoomOver: room == ", base.Get("room", v))
					roomInfo := base.Get("room",v ).(base.Pk)
					for _,user := range roomInfo.Players{
						if nil == user{
							continue
						}

						if user.PlayerId <= 0{
							continue
						}
						userInfo := base.Get("user",user.PlayerId).(base.PlayerInfo)
						userInfo.RoomNo  = 0
						userInfo.Online = true
						if userInfo.UsedItem != 0{
							// todo 退出时房间还有人 判断退还物品并且房间id清0
							log.Debug("-------------userInfo.UsedItem is:",userInfo.UsedItem)

							ItemInfoInt := base.Get("item",userInfo.UsedItem)
							if nil == ItemInfoInt{
								return
							}
							itemInfo :=ItemInfoInt.(base.ItemInfo)
							playerId := itemInfo.UserID
							status := itemInfo.Status
							itemId := itemInfo.ItemID

							if status == 1{
								return
							}
							playerInfo := base.Get("user",playerId).(base.PlayerInfo)
							playerInfo.ItemId = append(playerInfo.ItemId, itemId)
							base.Put("user",playerId,playerInfo)
							userInfo.UsedItem = 0
							base.Delete("item", userInfo.UsedItem)
						}
						base.Put("user",user.PlayerId,userInfo)
						MSG_RoomStateS2C := &msg.MsgRoomStateS2C{
							RoomState:int32(msg.RoomState_NULL),
							Time:0,
							EggOwner:0,

						}
						if base.InitConn[user.PlayerId] !=  nil{
							// todo 挂机通知返回房间
							base.InitConn[user.PlayerId].WriteMsg(MSG_RoomStateS2C)
						}

					}
					roomInfo.Players = nil
					log.Info("RoomOver: room == ", base.Get("room", v))
					base.Delete("room", v)
					log.Info("RoomOver: room == ", base.Get("room", v))
					log.Info("RoomOver: RoomOver == ", base.RoomList)
					kk := k + 1
					base.RoomList = append(base.RoomList[:k], base.RoomList[kk:]...)
					k--
					base.RoomPool = append(base.RoomPool, v)
					log.Info("RoomList: RoomList == ", base.RoomList, k)
				} else if len(room.Players) > 0 {
					for _, val := range room.Players {
						if nil == val{
							continue
						}
						useerInfo := base.Get("user",val.PlayerId).(base.PlayerInfo)
						// 更新金币
						updateGolden(val.PlayerId -conf.Server.BaseNum, useerInfo.Gold)
						updateScore(val.PlayerId -conf.Server.BaseNum, useerInfo.Score)
						updateItem(val.PlayerId -conf.Server.BaseNum, useerInfo.ItemId)
						updateUsedItem(val.PlayerId -conf.Server.BaseNum, useerInfo.UsedItem)
					}
				}
			} else {
				base.Delete("room", v)
				kk := k + 1
				base.RoomList = append(base.RoomList[:k], base.RoomList[kk:]...)
				k--
			}
		}

	} else {
		log.Info("RoomList: no room data")
	}
}

// 更新房卡
func updateCard(uin, num uint) {
	o := orm.NewOrm()
	n, err := o.QueryTable(new(TAccount)).Filter("uin", uin).Update(orm.Params{
		"cards":      orm.ColValue(orm.ColMinus, num),
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

// 更新道具状态
func updateUsedItem(uin, num int32) {
	log.Debug("更新道具状态")
	o := orm.NewOrm()

	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"UsedItem":      num,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

// 更新金币
func updateGolden(uin, num int32) {
	log.Debug("更新金币")
	o := orm.NewOrm()

	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"golden":      num,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

// 更新积分
func updateScore(uin, num int32) {
	log.Debug("更新积分")
	o := orm.NewOrm()
	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"score":      num,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

// 更新道具
func updateItem(uin int32, Items []int32) {
	log.Debug("更新道具")
	o := orm.NewOrm()
	var itemString string
	b,_ := json.Marshal(Items)
	itemString = bytes2str(b)

	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"Items":      itemString,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update Items err = ", err)
	} else {
		log.Info("RoomOver: success Items = ", n)
	}
}

// 更新名字
func updateName(uin int32, name string) {
	log.Debug("更新名字",uin)
	uin  = uin - conf.Server.BaseNum
	o := orm.NewOrm()
	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"Nick":     name,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

func updateNameNum(uin int32, num int32) {
	log.Debug("updateNameNum")
	uin  = uin - conf.Server.BaseNum
	o := orm.NewOrm()
	account := TAccount{
		Uin:uint(uin),
	}

	err := o.Read(&account,"Uin")
	log.Debug("account",account)

	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"NickNum":     account.NickNum + num,
		"updateTime": time.Now(),
	})

	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

// 更新鸟id
func updateBird(uin, num int32) {
	log.Debug("更新鸟id",uin,num)
	uin  = uin - conf.Server.BaseNum
	o := orm.NewOrm()
	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"BirdId":      num,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}

func updateBirdNum(uin, num int32) {
	log.Debug("更新鸟id")
	uin  = uin - conf.Server.BaseNum
	o := orm.NewOrm()

	account := TAccount{
		Uin:uint(uin),
	}

	err := o.Read(&account,"Uin")
	log.Debug("account",account)

	n, err := o.QueryTable(new(TAccount)).Filter("Uin", uin).Update(orm.Params{
		"BirdId":      account.BirdIdNum + num,
		"updateTime": time.Now(),
	})
	if err != nil {
		log.Error("RoomOver: update card err = ", err)
	} else {
		log.Info("RoomOver: success num = ", n)
	}
}


func updateUawe(uin int32) {
	log.Debug("更新鸟id",uin)

	playerInfoInt := base.Get("user",uin)
	if nil == playerInfoInt{
		return
	}
	playerInfo := playerInfoInt.(base.PlayerInfo)
	golden := playerInfo.Gold
	items := playerInfo.ItemId
	usedItem := playerInfo.UsedItem

	updateGolden(uin -conf.Server.BaseNum,golden)
	updateItem(uin -conf.Server.BaseNum,items)
	updateUsedItem(uin-conf.Server.BaseNum,usedItem)
}

func str2bytes(s string) []byte {
	x := (*[2]uintptr)(unsafe.Pointer(&s))
	h := [3]uintptr{x[0], x[1], x[1]}
	return *(*[]byte)(unsafe.Pointer(&h))
}

func bytes2str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 获取用户登录信息
func getUser(args []interface{}) base.PlayerInfo {
	o := orm.NewOrm()

	login := args[0].(*msg.MsgLogin)
	OpenID := login.GetOpenId();
	Url := login.GetIconUrl();
	Nick := login.GetNickName();
	log.Debug("User: OpenID = ", OpenID)
	account := TAccount{
		OpenId: OpenID,
		HeadUrl: Url,
		Nick: Nick,
	}

	exit,value ,err := o.ReadOrCreate(&account,"openId")
	fmt.Println("exit",exit)
	fmt.Println("value",value)

	if err != nil {
		log.Debug("User: account err is:" , err)
		return base.PlayerInfo{}
	}

	fmt.Println("account OpenId",account.OpenId)
	fmt.Println("account Uin",account.Uin)
	if account.BirdId == 0{
		account.BirdId = int32(rand.Intn(3) + 1)
		fmt.Println("account.BirdId",account.BirdId)
		updateBird(int32(account.Uin) + conf.Server.BaseNum,account.BirdId )
	}

	var items []int32
	json.Unmarshal(str2bytes(account.Items),&items)
	log.Debug("-=-=-=-=-items ",str2bytes(account.Items),items)

	userinfo := base.PlayerInfo{
		PlayerId: int32(account.Uin) + conf.Server.BaseNum,
		NickName:   account.Nick,
		IconUrl: account.HeadUrl,
		Gold:   int32(account.Golden),
		Score:  int32(account.Score),
		OpenId: OpenID,
		BirdID: account.BirdId,
		BirdNum:account.BirdIdNum,
		NameNum:account.NickNum,
		ItemId:	items,
		UsedItem:account.UsedItem,
	}
	fmt.Println("base.userinfo",userinfo)
	return userinfo
	//}
}

// 获取排名
func getRankGolden(args []interface{}) (userList []int32) {
	log.Debug("getRankGolden ")

	var users []TAccount
	_, err := orm.NewOrm().QueryTable(new(TAccount)).Limit(20).OrderBy("Golden").All(&users)

	for _,user := range users{
		userList= append(userList, int32(user.Uin) + conf.Server.BaseNum)

	}
	log.Debug("userList ", userList)

	if err != nil {
		log.Debug("User: account err is:" , err)
		return
	}

	fmt.Println("users.userinfo",users)
	return userList
}


// post 网络请求 ,params 是url.Values类型
func post(params url.Values) (rs []byte, err error) {
	resp, err := http.PostForm(conf.Server.CheckCard, params)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}
